Skip to content

fix(pack): ship static web assets in module .nupkgs#125

Merged
antosubash merged 2 commits intomainfrom
claude/fix-users-packaging-bug-OkX0Q
Apr 29, 2026
Merged

fix(pack): ship static web assets in module .nupkgs#125
antosubash merged 2 commits intomainfrom
claude/fix-users-packaging-bug-OkX0Q

Conversation

@antosubash
Copy link
Copy Markdown
Owner

@antosubash antosubash commented Apr 29, 2026

Summary

SimpleModule.Users 0.0.33 (and every other UI-shipping module) was published with an empty staticwebassets/ tree, so consumers got a 404 for /_content/SimpleModule.Users/SimpleModule.Users.pages.js and the login page rendered blank. Two independent root causes; this PR fixes both, and adds a CI smoke test so the next regression of this shape is caught at PR time.

Root causes

  1. Release workflow never built the JS. publish-nuget ran npm ci then jumped straight to dotnet pack, with no npm run build in between. On a clean CI checkout each module's wwwroot/ was empty when pack ran, so the SDK had nothing to package.

  2. Microsoft.NET.Sdk.StaticWebAssets evaluates Content Include="wwwroot/**" during MSBuild item evaluation, which runs before any target executes. Even with the existing JsBuild MSBuild target (BeforeTargets="Build"), the SDK had already locked in an empty file list by the time Vite ran. So dotnet pack invoked outside the workflow (or after a git clean) would still produce an empty package — the workflow fix alone wasn't enough.

Changes

1. npm run build before dotnet pack (release workflow)

Inserted between npm ci and dotnet restore in .github/workflows/release.yml so module wwwroot/ directories are populated before pack runs. Belt-and-suspenders alongside the MSBuild fix below; also a perf win because the orchestrator builds modules in parallel.

2. MSBuild: pre-populate @(Content) from built wwwroot/ (modules/Directory.Build.targets)

  • Broadened JsBuild's BeforeTargets to also fire before ResolveStaticWebAssetsConfiguration, ResolveProjectStaticWebAssets, GetCopyToOutputDirectoryItems, and GenerateNuspec — covers dotnet pack invoked outside the Build chain.
  • Added a ReincludeWwwrootContent target (AfterTargets="JsBuild" BeforeTargets="ResolveProjectStaticWebAssets") that re-adds wwwroot/** to @(Content) from inside MSBuild execution, after Vite has run. This is the actual fix for the cold-build case — without it, dotnet pack from a clean checkout still produces an empty staticwebassets/ tree even with the workflow fix.

3. CI smoke job (pack-smoke) + verification script

  • New scripts/verify-nupkg-static-assets.mjs discovers UI-shipping modules (modules/*/src/*/ with a package.json next to a .csproj and a Pages/index.ts), then asserts each matching .nupkg contains:
    • staticwebassets/{Id}.pages.js (the SDK strips the wwwroot/ prefix when packaging)
    • at least one .mjs code-split chunk under staticwebassets/
    • build/{Id}.props (the manifest plumbing consumers need to pick up the assets)
  • New pack-smoke job in .github/workflows/ci.yml runs dotnet pack exactly the way release does, then runs the verifier — so the next time a module ships an empty package, CI fails before merge.

Verification

Locally, with everything cleaned (rm -rf wwwroot obj bin):

  • Cold pack of SimpleModule.Users: now 89 entries including staticwebassets/SimpleModule.Users.pages.js, all .mjs chunks, and build/SimpleModule.Users.props.
  • Cold pack of SimpleModule.Settings: now 29 entries including staticwebassets/SimpleModule.Settings.pages.js, the smaller chunk set, and build/SimpleModule.Settings.props.
  • Warm-cache repack: identical output, no duplicate Content items (verified the Exclude="@(Content)" guard works).
  • Verifier passes for both packed modules; correctly fails when a module's .nupkg is missing (regression check).

Test plan

  • CI's new pack-smoke job runs npm run build + dotnet pack + verifier and reports green.
  • On the next release, inspect a published module .nupkg (e.g. SimpleModule.Users 0.0.34) and confirm it contains staticwebassets/SimpleModule.Users.pages.js, the .mjs chunks, and build/SimpleModule.Users.props.
  • Reference the new package version from a fresh consumer app and verify /_content/SimpleModule.Users/SimpleModule.Users.pages.js returns 200 and the login page renders end-to-end.

Without 'npm run build' between 'npm ci' and 'dotnet pack', module
wwwroot/ directories are empty on a clean CI checkout, so packed NuGets
omit the staticwebassets/ tree. Consumers of SimpleModule.Users (and
every other module shipping a React UI) then see 404s for
/_content/{Module}/{Module}.pages.js.
@cloudflare-workers-and-pages
Copy link
Copy Markdown

cloudflare-workers-and-pages Bot commented Apr 29, 2026

Deploying simplemodule-website with  Cloudflare Pages  Cloudflare Pages

Latest commit: db64e20
Status: ✅  Deploy successful!
Preview URL: https://435d6100.simplemodule-website.pages.dev
Branch Preview URL: https://claude-fix-users-packaging-b.simplemodule-website.pages.dev

View logs

@antosubash antosubash marked this pull request as ready for review April 29, 2026 15:30
The StaticWebAssets SDK evaluates 'Content Include="wwwroot/**"' during
MSBuild item evaluation, which runs before any target executes. On a
fresh checkout wwwroot/ does not exist yet, so the SDK locks in an empty
content list before JsBuild has a chance to run Vite. The previous
'BeforeTargets="Build"' on JsBuild was insufficient for two reasons:
the SDK had already enumerated the empty directory, and several pack-
relevant targets (ResolveProjectStaticWebAssets, GenerateNuspec) ran
outside the Build dependency chain.

Two changes:

1. Broaden JsBuild's BeforeTargets so it fires before
   ResolveStaticWebAssetsConfiguration, ResolveProjectStaticWebAssets,
   GetCopyToOutputDirectoryItems, and GenerateNuspec, in addition to
   Build.

2. Add a ReincludeWwwrootContent target that re-adds wwwroot/** to
   @(Content) after JsBuild and before ResolveProjectStaticWebAssets,
   mirroring the SDK's own item include. This is what actually gets the
   freshly-built files in front of the static-web-asset pipeline on a
   cold build.

Also adds a CI smoke job (pack-smoke) and a verification script
(scripts/verify-nupkg-static-assets.mjs) that runs 'dotnet pack' the
same way release does, then asserts each UI-shipping module's .nupkg
contains 'staticwebassets/{Id}.pages.js', at least one .mjs chunk, and
'build/{Id}.props' — exactly the shape that was missing from
SimpleModule.Users 0.0.33.
@antosubash antosubash changed the title fix(release): build npm workspaces before dotnet pack fix(pack): ship static web assets in module .nupkgs Apr 29, 2026
@antosubash antosubash merged commit 2836d94 into main Apr 29, 2026
6 checks passed
@antosubash antosubash deleted the claude/fix-users-packaging-bug-OkX0Q branch April 29, 2026 15:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants